package com.example.videopractice.camera

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.ImageFormat
import android.hardware.Camera
import android.hardware.camera2.CameraCaptureSession
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CameraManager
import android.hardware.camera2.params.OutputConfiguration
import android.hardware.camera2.params.SessionConfiguration
import android.media.Image
import android.media.ImageReader
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.Surface
import android.view.SurfaceHolder
import androidx.annotation.RequiresApi
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.base.base.BaseBindingActivity
import com.example.base.util.ALog
import com.example.videopractice.databinding.ActivityCameraBinding
import java.util.concurrent.Executors
import kotlin.math.min

/**
 * Camera2 的使用 demo
 */
class CameraActivity : BaseBindingActivity<ActivityCameraBinding>() {

    private var camera: Camera? = null
    private var camera2: CameraDevice? = null
    private var cameraManager: CameraManager? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        requestMultiplePermissions.launch(
            arrayOf(
                Manifest.permission.CAMERA,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            )
        )

        cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
        //只能onViewCreate里打开相机，不然都是黑屏
        //previewCamera()
        //previewCamera2(binding.surfaceView.holder.surface)
        previewCameraX()
        // 使用TextureView的
//        binding.textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
//            override fun onSurfaceTextureAvailable(surfaceTexture: SurfaceTexture, p1: Int, p2: Int) {
//                previewCamera2(Surface(surfaceTexture))
//            }
//
//            override fun onSurfaceTextureSizeChanged(surfaceTexture: SurfaceTexture, p1: Int, p2: Int) {
//
//            }
//
//            override fun onSurfaceTextureDestroyed(surfaceTexture: SurfaceTexture) = false
//
//            override fun onSurfaceTextureUpdated(p0: SurfaceTexture) {
//
//            }
//        }
    }

    //旧版camera的预览，已经过时
    private fun previewCamera() {
        camera = Camera.open()
        camera?.setDisplayOrientation(90)
        binding.surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
            override fun surfaceCreated(surfaceHolder: SurfaceHolder) {
                camera?.setPreviewDisplay(surfaceHolder)
                val parameter = camera?.parameters
                parameter?.previewFormat = ImageFormat.NV21
                camera?.parameters = parameter
                camera?.setPreviewCallback { bytes, camera ->
                    ALog.e("xiao", "NV21: $bytes")
                }
                camera?.startPreview()
            }

            override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) {

            }

            override fun surfaceDestroyed(p0: SurfaceHolder) {
                camera?.release()
            }
        })
    }

    private fun previewCamera2(surface: Surface) {

        val cameraIdList = cameraManager!!.cameraIdList
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.CAMERA
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ALog.e("xiao", "无相机权限")
            return
        } else {
            //handler： 用于指定调用该回调的线程。如果不指定则置null，此时系统会默认使用当前线程的looper。当需要将该回调放到后台线程处理时，可通过指定该handler的looper来设置：
            cameraManager?.openCamera(cameraIdList[0], object : CameraDevice.StateCallback() {
                override fun onOpened(camera: CameraDevice) {
                    //当camera成功打开之后会回调该方法。此时camera已经就绪，可以开始对相机进行一系列的操作，
                    //可通过调用CameraCaptureSession.createCaptureSession方法来设置第一个capture session
                    onOpenCamera2(camera, surface)
                }

                override fun onDisconnected(camera: CameraDevice) {
                    //当camera不再可用，或调用CameraManager.openCamera()打开相机失败时都会
                    //调用此方法.此时任何尝试调用CameraDevice方法的操作都会失败并抛出一个
                    //CameraAccessException异常。
                    //安全策略或权限的改变、可移动相机设备的物理断开、或者当该camera需要更高优
                    //先级的camera API Client时都会导致该camera设备连接断开
                }

                override fun onError(camera: CameraDevice, p1: Int) {
                    //顾名思义。当camera出错时会回调该方法
                    //应在该方法调用CameraDevice.close()和做一些其他释放相机资源的操作，防止相机出错而导致一系列问
                }

                override fun onClosed(camera: CameraDevice) {
                    super.onClosed(camera)
                    //当调用CameraDevice.close()关闭相机设备后会回调此方法。camera为别关闭的相机设备。
                    //该方法被回调执行后，任何尝试调用camera相关的操作都会失败，并且抛出一个IllegalStateException异常
                }
            }, null)
        }
    }

    private fun previewCameraX() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener(Runnable {
            val cameraX = cameraProviderFuture.get()

            val preview = Preview.Builder().build()
            preview.setSurfaceProvider(binding.preview.surfaceProvider)

            val imageAnalyzer = ImageAnalysis.Builder().build()
            imageAnalyzer.setAnalyzer(Executors.newSingleThreadExecutor(), { image ->
                if (image.format == ImageFormat.YUV_420_888) {
                    /**
                     * YUV_420_888是一种Y：U：V按4：1：1的比例进行采样的格式，也就是说其中每一个UV都被四个Y共享， 888表示每一个分量都是８bits
                     * NV21也是这种YUV_420的采样格式，只是其中U，V分量的排列不一样．
                     * Y，U，V的数据是分别存储在３个plane中的；
                     * plane#0为Y分量，plane#1为U分量，plane#2为V分量；
                     **/
                    ALog.e("xiao", "Y: ${image.planes[0].buffer}")
                    ALog.e("xiao", "U: ${image.planes[1].buffer}")
                    ALog.e("xiao", "V: ${image.planes[2].buffer}")
                }
                image.close()
            })

            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            try {
                cameraX.unbindAll()
                cameraX.bindToLifecycle(this, cameraSelector, preview, imageAnalyzer)
            } catch (e: Exception) {
                Log.e("xiao", "Use case binding failed", e)
            }

        }, ContextCompat.getMainExecutor(this))
    }

    private fun onOpenCamera2(cameraDevice: CameraDevice, surface: Surface) {
        // 要获取每一帧的预览数据，我们需要ImageReader这个类的帮助
        // maxImages 用户希望同时访问的最大映像数。这个值应该尽可能小，以限制内存的使用。一旦用户获得了maxImages Images，在通过AcquireLatestImage()或AcquireNextImage()访问新的Image之前，必须释放其中的一个Image。必须大于0。
        val reader = ImageReader.newInstance(
            binding.surfaceView.width,
            binding.surfaceView.width,
            ImageFormat.YUV_420_888, // camera2不支持NV21,官方推荐用YUV_420_888
            2
        )
        reader.setOnImageAvailableListener({ imageReader ->
            val image = imageReader.acquireNextImage()
            if (image.format == ImageFormat.YUV_420_888) {
                /**
                 * YUV_420_888是一种Y：U：V按4：1：1的比例进行采样的格式，也就是说其中每一个UV都被四个Y共享， 888表示每一个分量都是８bits
                 * NV21也是这种YUV_420的采样格式，只是其中U，V分量的排列不一样．
                 * Y，U，V的数据是分别存储在３个plane中的；
                 * plane#0为Y分量，plane#1为U分量，plane#2为V分量；
                 **/
                ALog.e("xiao", "Y: ${image.planes[0].buffer}")
                ALog.e("xiao", "U: ${image.planes[1].buffer}")
                ALog.e("xiao", "V: ${image.planes[2].buffer}")
            }
            image.close()
        },null)

        val stateCallback = object : CameraCaptureSession.StateCallback() {
            @RequiresApi(Build.VERSION_CODES.P)
            override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
                val builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
                // 将CaptureRequest的构建器与Surface对象绑定在一起
                builder.addTarget(surface)
                builder.addTarget(reader.surface)
                cameraCaptureSession.setRepeatingRequest(builder.build(), null, null)
                //
            }

            override fun onConfigureFailed(cameraCaptureSession: CameraCaptureSession) {
                ALog.e("xiao", "onConfigureFailed")
            }
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            // android 9以上的相机打开方式
            val sessionConfiguration = SessionConfiguration(
                SessionConfiguration.SESSION_REGULAR,
                listOf(OutputConfiguration(surface), OutputConfiguration(reader.surface)),
                mainExecutor,
                stateCallback
            )
            cameraDevice.createCaptureSession(sessionConfiguration)
        } else {
            //创建CaptureSession会话。第一个参数 outputs 是一个 List 数组，相机会把捕捉到的图片数据传递给该参数中的 Surface 。第二个参数 StateCallback 是创建会话的状态回调。第三个参数描述了 StateCallback 被调用时所在的线程
            cameraDevice.createCaptureSession(
                listOf(surface, reader.surface),
                stateCallback,
                null
            )
        }
    }

    // take YUV data from image, output data format-> YYYYYYYYUUVV
    private fun readYuvDataToBuffer(image: Image, data: ByteArray): Boolean {
        if (image.format != ImageFormat.YUV_420_888) {
            throw IllegalArgumentException("only support ImageFormat.YUV_420_888 for mow")
        }
        val imageWidth = image.width
        val imageHeight = image.height
        val planes = image.planes
        var offset = 0
        for (plane in planes.indices) {
            val buffer = planes[plane].buffer ?: return false
            val rowStride = planes[plane].rowStride
            val pixelStride = planes[plane].pixelStride
            val planeWidth = if (plane == 0) imageWidth else imageWidth / 2
            val planeHeight = if (plane == 0) imageHeight else imageHeight / 2
            if (pixelStride == 1 && rowStride == planeWidth) {
                buffer.get(data, offset, planeWidth * planeHeight)
                offset += planeWidth * planeHeight
            } else {
                // Copy pixels one by one respecting pixelStride and rowStride
                val rowData = ByteArray(rowStride)
                var colOffset: Int
                for (row in 0 until planeHeight - 1) {
                    colOffset = 0
                    buffer.get(rowData, 0, rowStride)
                    for (col in 0 until planeWidth) {
                        data[offset++] = rowData[colOffset]
                        colOffset += pixelStride
                    }
                }
                // Last row is special in some devices:
                // may not contain the full |rowStride| bytes of data
                colOffset = 0
                buffer.get(rowData, 0, min(rowStride, buffer.remaining()))
                for (col in 0 until planeWidth) {
                    data[offset++] = rowData[colOffset]
                    colOffset += pixelStride
                }
            }
        }
        return true
    }


    /**
     * 查询Camera2功能支持情况
     */
    private fun getCamera2HardwareSupport() {
        // cameraCharacteristics: 相机设备的属性类,
        // 通过 CameraManager 的 getCameraCharacteristics(String cameraId) 方法获取指定相机设备的 CameraCharacteristics 对象
        val cameraManager = cameraManager ?: return
        val cameraIdList = cameraManager.cameraIdList
        // 这里直接拿第一个摄像头
        val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraIdList[0])
        val deviceLevel =
            cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ?: return
        when (deviceLevel) {
            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY -> {
            }
            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED -> {
            }
            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL -> {
            }
            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3 -> {
            }
            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL -> {
            }
        }
    }
}